package cn.opencodes.framework.core.shiro;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.opencodes.framework.autoconfigure.properties.AlphaProperties;
import cn.opencodes.framework.core.service.AlphaService;
import cn.opencodes.framework.core.utils.SpringUtils;
import cn.opencodes.framework.core.utils.WebUtils;
import cn.opencodes.framework.core.vo.UserRoot;
import cn.opencodes.framework.tools.utils.StringUtils;
import cn.opencodes.framework.tools.vo.CoreConst;
import io.jsonwebtoken.Claims;

/**
 * Token权限过滤器
 * @author HJ
 */
public class AuthcTokenFilter extends AuthenticatingFilter {
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	public static final String HEADER_TOKEN_KEY = JwtTokenGen.HEADER;
	
	private AlphaService commonSev;
	private JwtTokenGen jwtTokenGen;
	private AlphaProperties props;

	public AuthcTokenFilter(AlphaProperties props){
		this.props = props;
	}
	
    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
    	String token = WebUtils.getRequestToken(request);
        UserRoot user = WebUtils.getUser();
        return new AuthcTokenBean(user.getId(), token);
    }
    
    @Override
    public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception {
    	super.afterCompletion(request, response, exception);
    	/**清除每一次请求登陆信息**/
    	org.apache.shiro.SecurityUtils.getSubject().logout();
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
    	HttpServletRequest req = WebUtils.toHttp(request);
    	logger.debug("拦截URL：{}", WebUtils.getPathWithinApplication(req));
    	//如果是登录请求则放行
    	if (isLoginRequest(request, response)) {
			return true;
		}
    	if (commonSev == null) {
    		commonSev = SpringUtils.getBean(AlphaService.class);
		}
    	if (jwtTokenGen == null) {
    		jwtTokenGen = SpringUtils.getBean(JwtTokenGen.class);
		}
        return false;
    }

	@Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
    	//获取请求token
		String token = WebUtils.getRequestToken(request);
		//仅开发环境调试
    	if (props.getDebug()>0 && props.getActive().equals("dev")) {
    		token = jwtTokenGen.generateToken(props.getDebug());
		}
		if(StringUtils.isBlank(token)){
			WebUtils.write(response, CoreConst.HttpStatus.PARAM_BLANK.value(), HEADER_TOKEN_KEY + "不能为空");
			return false;
		}
		//验证失效
		Claims claims = jwtTokenGen.getClaimByToken(token);
		if(claims == null || jwtTokenGen.isTokenExpired(claims.getExpiration())){
			WebUtils.write(response, CoreConst.HttpStatus.TOKEN_EXPIRED.value(), HEADER_TOKEN_KEY + "失效，请重新登录");
			return false;
		}
		//用户下线
		long userId = Long.parseLong(claims.getSubject());
		UserRoot user = commonSev.getUserRootInfo(userId);
		if (user==null || user.isKickout()) {
			WebUtils.write(response, CoreConst.HttpStatus.TOKEN_EXPIRED.value(), "您已被踢下线，请重新登录");
			return false;
		}
		//已登录的用户信息存到request域，方便mvc层之间调用
		WebUtils.setUser(user);
        return executeLogin(request, response);
    }
	
    
}
